// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

part of dart.core;

/**
 * 对象的集合，其中每个对象只能出现一次。
 *
 * 也就是说，对于元素类型的每个对象，对象要么被认为是在Set中，要么不在Set中。
 *
 * Set实现也许会认为一些元素是没有区别的。
 * 对于Set中的任何操作，这些元素作为相同的对象被处理。
 *
 * 默认的[Set]实现是[LinkedHashSet]，
 * 如果对于操作符[Object.==]元素对象相等的话，则认为它们是没有区别的。
 *
 * 迭代Set中的元素时，某些时候有可能是无序的，也有可能是有序的。例如：
 *
 * * [HashSet]是无序的，这意味着它迭代的顺序是不确定的
 * * [LinkedHashSet]按元素的插入顺序进行迭代
 * * [SplayTreeSet]按排序顺序迭代元素
 *
 * 当Set的一个操作正在执行的时候，通常不允许修改Set（添加或删除元素），
 * 例如，在调用[forEach]或[containsAll]期间。
 * 在迭代Set或任何由Set提供支持的[Iterable]时，也不允许修改Set，
 * 例如，[where]或[map]方法的返回对象。
 */
abstract class Set<E> extends Iterable<E> implements EfficientLength {
  /**
   * 创建一个空的[Set]。
   *
   * 创建的[Set]是一个普通的[LinkedHashSet]。
   * 因此，它认为相等（使用[==]判断，并实现[Object.hashCode]）的元素是没有区别的。
   *
   * 该构造函数等同于`new LinkedHashSet<E>()`。
   */
  factory Set() = LinkedHashSet<E>;

  /**
   * 创建一个空的，元素严格相等的[Set]。
   *
   * 被创建的[Set]是一个使用identity作为相等关系的[LinkedHashSet]。
   * 也就是说使用`identical(Object a, Object b)`判断元素对象是否相等。
   *
   * 该构造函数等同于`new LinkedHashSet<E>.identity()`。
   */
  factory Set.identity() = LinkedHashSet<E>.identity;

  /**
   * 创建一个包含所有[elements]的[Set]。
   *
   * 所有[elements]应该可以对[E]赋值。
   * 可迭代对象`elements`的元素可能是任何类型，
   * 所以此构造函数可用于down-cast转换，例如：
   *
   *     Set<SuperType> superSet = ...;
   *     Set<SubType> subSet =
   *         new Set<SubType>.from(superSet.where((e) => e is SubType));
   *
   * 被创建的[Set]是一个[LinkedHashSet]。
   * 因此，它认为相等（使用[==]判断，并实现[Object.hashCode]）的元素是没有区别的。
   *
   * 该构造函数等同于`new LinkedHashSet<E>.from(elements)`。
   */
  factory Set.from(Iterable elements) = LinkedHashSet<E>.from;

  /**
   * 用于迭代所有元素的迭代器。
   *
   * 迭代的顺序是由不同的`Set`实现定义的，但是对Set的更改必须保持一致。
   */
  Iterator<E> get iterator;

  /**
   * 如果[value]在Set中，返回true。
   */
  bool contains(Object value);

  /**
   * 将[value]添加到Set中。
   *
   * 如果[value]（或相等的值）还不在Set中，返回`true`。
   * 否则，返回`false`，并且Set不变。
   *
   * 例子：
   *
   *     var set = new Set();
   *     var time1 = new DateTime.fromMillisecondsSinceEpoch(0);
   *     var time2 = new DateTime.fromMillisecondsSinceEpoch(0);
   *     // time1 and time2 are equal, but not identical.
   *     Expect.isTrue(time1 == time2);
   *     Expect.isFalse(identical(time1, time2));
   *     set.add(time1);  // => true.
   *     // A value equal to time2 exists already in the set, and the call to
   *     // add doesn't change the set.
   *     set.add(time2);  // => false.
   *     Expect.isTrue(set.length == 1);
   *     Expect.isTrue(identical(time1, set.first));
   */
  bool add(E value);

  /**
   * 将所有[elements]添加到Set中。
   *
   * 等同于使用[add]添加每个[elements]中的元素，但一些集合可能做了优化。
   */
  void addAll(Iterable<E> elements);

  /**
   * 从Set中删除[value]。
   * 如果[value]在Set中，返回true。否则，返回false。
   * 如果[value]不在Set中，方法不会产生任何效果。
   */
  bool remove(Object value);

  /**
   * 在Set中，如果一个元素等于[object]，返回元素。
   *
   * 检查Set中是否有元素等于[object]。
   * 如果存在，返回元素，否则返回`null`。
   */
  E lookup(Object object);

  /**
   * 从`this`中删除[elements]的每个元素。
   */
  void removeAll(Iterable<Object> elements);

  /**
   * 删除不在[elements]中的所有元素。
   *
   * 检查[elements]中的每个元素是否等于`this`中的元素（根据`this.contains`），
   * 如果是的话，`this`中相等的元素会被保留，与`elements`中任何元素都不等的元素则被删除。
   */
  void retainAll(Iterable<Object> elements);

  /**
   * 删除所有满足[test]的元素。
   */
  void removeWhere(bool test(E element));

  /**
   * 删除所有不满足[test]的元素。
   */
  void retainWhere(bool test(E element));

  /**
   * 返回`this`是否包含[other]的所有元素。
   */
  bool containsAll(Iterable<Object> other);

  /**
   * 返回一个新的Set，它是`this`和[other]的交集。
   *
   * 也就是说，返回的Set中的元素，
   * 根据`Set.contains`计算，既包含在`this`中，也包含在[other]中。
   */
  Set<E> intersection(Set<Object> other);

  /**
   * 返回一个新的Set，它包含`this`和[other]的所有元素（并集）。
   */
  Set<E> union(Set<E> other);

  /**
   * 返回一个新的Set，它是`this`和[other]的差集，包含属于`this`，且不属于[other]的所有元素。
   *
   * 根据`other.contains`判断元素不在[other]中。
   */
  Set<E> difference(Set<E> other);

  /**
   * 删除Set中的所有元素。
   */
  void clear();

  /**
   * 用与`this`相同的元素和行为，创建一个新的[Set]。
   *
   * 对于添加和删除元素，返回的Set的行为与`this`相同。它初始化包含相同的元素。
   * 如果`this`指定了元素的顺序，返回的Set顺序也相同。
   */
  Set<E> toSet();
}
